package test.hash;

/**
 * Created by linshuo on 2018/4/18.
 * <p>
 * JDK的hashcode源码分析
 */
public class JDKHashcode {

    /**
     * The value is used for character storage.
     */
    static char value[];

    /**
     * The offset is the first index of the storage that is used.
     */
    static int offset;

    /**
     * The count is the number of characters in the String.
     */
    static int count;

    /**
     * Cache the hash code for the string
     */
    static int hash; // Default to 0

    /**
     * JDK: HashMap中实现的hash算法(再hash算法)
     *
     * @param h
     * @return
     */
    static int hash(int h) {
        /*
         This function ensures that hashCodes that differ only by
         constant multiples at each bit position have a bounded
         number of collisions (approximately 8 at default load factor).
        */
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    /**
     * JDK: String类实现的hashcode方法源代码
     *
     * @param str
     * @return
     */
    static int hashCodeJDK(String str) {
        // 右边的hash是作为缓存
        int h = hash;
        if (h == 0) {
            int off = 0;
            char val[] = str.toCharArray();
            int len = str.length();
            for (int i = 0; i < len; i++) {
                h = 31 * h + val[off++];
            }
            hash = h;
        }
        return h;
    }

    // String类的hashcode值（哈希值）是如何计算得到的？具体实现？为了方便阅读，我们来进行分步说明
    static void hashcodeTest() {
        String str = "shuoGG";
        // 第一步 = (int)'y'
        // 第二步 = (31 * (int)'y') + (int)'a'
        // 第三步 = 31 * ((31 * (int)'y') + (int)'a') + (int)'n'
        // 第四步 = 31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g'
        // 第五步 = 31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c'
        // 第六步 = 31 * (31 * (31 * (31 * ((31 * (int)'y') + (int)'a') + (int)'n') + (int)'g') + (int)'c') + (int)'q'

        // 上面的过程，也可以用下面的方式表示

        // 第一步 = (int)'y'
        // 第二步 = 31 * (第一步的计算结果) + (int)'a'
        // 第三步 = 31 * (第二步的计算结果) + (int)'n'
        // 第四步 = 31 * (第三步的计算结果) + (int)'g'
        // 第五步 = 31 * (第四步的计算结果) + (int)'c'
        // 第六步 = 31 * (第五步的计算结果) + (int)'q'

        int hashcode = 31 * (31 * (31 * (31 * ((31 * (int) 'y') + (int) 'a') + (int) 'n') + (int) 'g') + (int) 'c') + (int) 'q';
        System.out.println("shuoGG的hashcode = " + hashcode);
        System.out.println("shuoGG的hashcode = " + str.hashCode());
    }

    /**
     * 测试自定义的hashcode方法
     */
    public static void main(String[] args) {
        String str = "shuoGG";
        System.out.println("我算的str的hashcode = " + new HashcodeOfString().hashCode(str));
        System.out.println("官方的str的hashcode = " + str.hashCode());
    }
}